﻿//Copyright (C) 2009  Jaco (ScionBot.com)

//This program is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.

//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.

//You should have received a copy of the GNU General Public License
//along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.IO;
using Scion.Misc;
using Scion.Library;

namespace Scion.Core
{
    /// <summary>
    /// This class basically executes all the randoms. Checking the random through the Check() method, and
    /// if the result is true, the process of solving the random will go under operation.
    /// </summary>
    public class Random
    {
        public List<Assembly> randomsAsmList;
        public List<object> randomObjectList;
        public List<Type> randomTypeList;

        Stub stub;
        
        public Random(Stub s)
        {
            stub = s;
        }

        public bool ProcessRandom(string assemblyName)
        {
            object randomObject;
            Type randomType;
            if (randomsAsmList == null)
                return true;
            Assembly random;
            try
            {
                random = Assembly.LoadFile(ScionSettings.StartupPath + @"\Randoms\" + assemblyName + ".dll");
            }
            catch
            { return false; }
            foreach (Type rndClass in random.GetTypes())
            {
                if (rndClass.IsSubclassOf(typeof(Superior)))
                {
                    foreach (ConstructorInfo constructor in rndClass.GetConstructors())
                    {
                        if (constructor.IsConstructor)
                        {
                            randomObject = constructor.Invoke(new object[] { stub });
                            randomType = randomObject.GetType();
                            MethodInfo[] methods = rndClass.GetMethods();
                            foreach (MethodInfo method in methods)
                            {
                                bool returnValue = false;
                                if ((method.Name == "Check") && method.IsPublic)
                                {
                                    returnValue = (bool)method.Invoke(randomObject, null);
                                    if (returnValue)
                                    {
                                        foreach (MethodInfo solveMethod in methods)
                                        {
                                            if ((solveMethod.Name == "Solve") && solveMethod.IsPublic)
                                                return (bool)solveMethod.Invoke(randomObject, null);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return true;
        }

        public bool ProcessAllRandoms()
        {
            if (randomsAsmList == null)
                return true;
            for (int i = 0; i < randomObjectList.Count; i++)
            {
                MethodInfo[] methods = randomTypeList[i].GetMethods();
                foreach (MethodInfo method in methods)
                {
                    bool returnValue = false;
                    if ((method.Name == "Check") && method.IsPublic)
                    {
                        returnValue = (bool)method.Invoke(randomObjectList[i], null);
                        if (returnValue)
                        {
                            foreach (MethodInfo solveMethod in methods)
                            {
                                if ((solveMethod.Name == "Solve") && solveMethod.IsPublic)
                                    return (bool)solveMethod.Invoke(randomObjectList[i], null);
                            }
                        }
                        else
                            goto NewRandom;
                    }
                }
            NewRandom:
                continue;
            }
            return true;
        }

        public void InitializeRandoms()
        {
            if (randomsAsmList == null)
                return;
            randomObjectList = new List<object>();
            randomTypeList = new List<Type>();
            foreach (Assembly random in randomsAsmList)
            {
                foreach (Type rndClass in random.GetTypes())
                {
                    if (rndClass.IsSubclassOf(typeof(Superior)))
                    {
                        foreach (ConstructorInfo constructor in rndClass.GetConstructors())
                        {
                            if (constructor.IsConstructor)
                            {
                                object randomObject = constructor.Invoke(new object[] { stub });
                                randomObjectList.Add(randomObject);
                                randomTypeList.Add(randomObject.GetType());
                            }
                        }
                    }
                }
            }
        }

        public void GetRandomDlls()
        {
            List<Assembly> randomsAssembly = new List<Assembly>();
            DirectoryInfo randomsLocation;
            randomsLocation = new DirectoryInfo(ScionSettings.StartupPath + @"\Randoms");
            if (!randomsLocation.Exists)
                return;
            foreach (FileInfo dllInfo in randomsLocation.GetFiles())
            {
                if (dllInfo.Name.IndexOf(".dll") > -1)
                {
                    randomsAssembly.Add(Assembly.LoadFile(dllInfo.FullName));
                }
            }
            if (randomsAssembly.Count < 1)
                return;
            randomsAsmList = randomsAssembly;
        }
    }
}
